package gwtI18nEditor.datamodel;

import gwtI18nEditor.tools.IteratorFilter;
import gwtI18nEditor.tools.IteratorWrapper;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Vector;

public class MessageFile implements DirectoryEntry, Iterable<Message> {

	private final Directory            parent;
	private final String               pkgname;
	private final String               identifier;
	private       String               header;
	private       String               footer;
	private final List<FileSection>    sections;
	private final Map<String, Message> index;
	private       int                  incompletes = 0;
	
	public MessageFile(Directory parent, String pkgname, String identifier, String header, String footer) {
		this.parent     = parent;
		this.pkgname    = pkgname;
		this.identifier = identifier;
		this.header     = header;
		this.footer     = footer;
		this.sections   = new ArrayList<FileSection>();
		this.index      = new HashMap<String, Message>();
	}
	
	public String getPackage() {
		return pkgname;
	}

	public String getIdentifier() {
		return identifier;
	}

	public String getHeader() {
		return header;
	}

	public void setHeader(String header) {
		this.header = header;
	}

	public String getFooter() {
		return footer;
	}

	public void setFooter(String footer) {
		this.footer = footer;
	}
	
	public Message addMessage(String identifier, MessageType type, String prefix, String infix, String suffix) {
		Message message = new Message(this, identifier, type, prefix, infix, suffix);
		sections.add(new FileSection(message));
		index.put(identifier, message);
		return message;
	}
	
	public Message addMessage(String identifier) {
		Message message = new Message(this, identifier);
		sections.add(new FileSection(message));
		index.put(identifier, message);
		return message;
	}
	
	public void addLiteral(String literal) {
		sections.add(new FileSection(literal));
	}
	
	public String buildFile() {
		StringBuilder result = new StringBuilder();
		result.append(header);
		for (FileSection section: sections) {
			if (section.isMessage()) {
				result.append(section.getMessage().getPrefix());
				result.append((section.getMessage().getType()==MessageType.SAFEHTML) ? "SafeHtml" : "String");
				result.append(section.getMessage().getInfix());
				result.append(section.getMessage().getIdentifier());
				result.append(section.getMessage().getSuffix());
			} else {
				result.append(section.getLiteral());
			}
		}
		result.append(footer);
		return result.toString();
	}

	@Override
	public Iterator<Message> iterator() {
		return new IteratorWrapper<FileSection, Message>(new IteratorFilter<FileSection>(sections.iterator()) {
			@Override
			protected boolean keep(FileSection item) {
				return item.isMessage();
			}
		}) {
			@Override
			public Message wrap(FileSection value) {
				return value.getMessage();
			}
		};
	}
	
	public void addTranslation(String identifier, Locale language, String content) {
		Message msg = index.get(identifier);
		if (msg==null) msg = addMessage(identifier);
		msg.addTranslation(language, content);
	}
	
	public int msgCount() {
		return index.size();
	}
	
	@Override
	public String toString() {
		return getIdentifier();
	}

	public Vector<Message> getMessages() {
		Vector<Message> result = new Vector<Message>();
		for (Message message: this)
			result.add(message);
		return result;
	}

	@Override
	public boolean isDirectory() {
		return false;
	}

	@Override
	public boolean needsAttention() {
		return incompletes > 0;
	}
	
	void addIncomplete() {
		incompletes++;
		if (incompletes==1) {
			Directory dir = parent;
			while (dir!=null) {
				dir.addIncomplete();
				dir = dir.parent;
			}
		}
	}
	
	void removeIncomplete() {
		incompletes--;
		if (incompletes==0) {
			Directory dir = parent;
			while (dir!=null) {
				dir.removeIncomplete();
				dir = dir.parent;
			}
		}
	}
	
	public void check(Locale... locales) {
		for (Message message: this)	message.check(locales);
	}
	
	public Map<String, String> buildFiles() {
		StringBuilder java = new StringBuilder();
		Map<Locale, StringBuilder> properties = new HashMap<Locale, StringBuilder>();
		java.append(header);
		for (FileSection section: sections) {
			if (section.isMessage()) {
				Message message = section.getMessage();
				java.append(message.getPrefix());
				java.append((message.getType()==MessageType.SAFEHTML) ? "SafeHtml" : "String");
				java.append(message.getInfix());
				java.append(message.getIdentifier());
				java.append(message.getSuffix());
				for (Translation translation: message.getTranslations()) {
					if (!translation.needsAttention()) {
						StringBuilder prop = properties.get(translation.getLocale());
						if (prop==null) {
							prop = new StringBuilder();
							properties.put(translation.getLocale(), prop);
						}
						prop.append(message.getIdentifier());
						prop.append("=");
						prop.append(translation.getMessage());
						prop.append("\r\n");
					}
				}
			} else {
				java.append(section.getLiteral());
			}
		}
		java.append(footer);
		Map<String, String> result = new HashMap<String, String>();
		result.put(getIdentifier()+".java", java.toString());
		for (Entry<Locale, StringBuilder> prop: properties.entrySet())
			result.put(getIdentifier()+((prop.getKey()==null) ? "" : ("_"+prop.getKey().getCode()))+".properties", prop.getValue().toString());
		return result;
/*		File dir = parent.getFile();
		File java = new File(dir, identifier+".java");
		HashMap<String, File> properties = new HashMap<String, File>();*/
	}
	
	public void save() {
		Map<String, String> files = buildFiles();
		for (Entry<String, String> entry: files.entrySet()) {
			try {
				File file = new File(parent.getFile(), entry.getKey());
				OutputStream out = new FileOutputStream(file);
				out.write(entry.getValue().getBytes("UTF-8"));
				out.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
